﻿using System;
using System.Collections.Generic;
using System.Drawing.Imaging;
using System.IO;
using System.Net;
using System.Net.Security;
using System.Resources;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Web;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media.Imaging;
using System.Windows.Threading;
using System.Xml;
using Microsoft.Win32;
using NO.I.Core;

namespace NO.I {
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window {
        private static OAuthWindow OAuthWindow;
        private static Dictionary<string, string> _oauthInfo;
        private static int MaxLength = 5 * 1024 * 1024;
        private byte[] _imageBuffer;
        private static string emptyContent = "输入你要咆哮的内容";
        private static int ContentMaxLength = 140;
        private int currentLength = emptyContent.Length * 2;
        private string currentContent = string.Empty;
        private Int64 _startTime;
        private DispatcherTimer _timer = new DispatcherTimer();
        private int _currentFrame = 0;
        private GifBitmapDecoder _decoder;

        /// <summary> 
        /// 要发布的微博文本内容，必须做URLencode，内容不超过140个汉字。
        /// </summary>
        private string _status = string.Empty;

        /// <summary>
        /// 要上传的图片，仅支持JPEG、GIF、PNG格式，图片大小小于5M。
        /// </summary>
        private byte[] _pic = null;

        /// <summary>
        /// OAuth授权后获得
        /// </summary>
        private string _access_token = string.Empty;

        private static string _updateURL = "https://api.weibo.com/2/statuses/update.json";
        private static string _uploadURL = "https://upload.api.weibo.com/2/statuses/upload.json";

        public byte[] ImageBuffer {
            get {
                return _imageBuffer;
            }
            set {
                _imageBuffer = value;
            }
        }

        public BitmapImage ImageSource {
            set {
                if (value != null) {
                    preview_Image.Source = value;
                }
            }
        }

        public MainWindow() {
            InitializeComponent();
            this.Dispatcher.BeginInvoke(new Action(LoadSession));
            _timer.Interval = TimeSpan.FromMilliseconds(100);
            _timer.Tick += new EventHandler(Wait);

            ///
            var wait = NO.I.Properties.Resources.wait;

            MemoryStream mx = new MemoryStream();
            wait.Save(mx, ImageFormat.Gif);

            _decoder = new GifBitmapDecoder(mx, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
        }

        private void Button_Public_Click(object sender, RoutedEventArgs e) {
            if (_oauthInfo == null || _oauthInfo.Count == 0 || CheckIsExprie()) {
                OAuthWindow = new OAuthWindow();
                OAuthWindow.AuthCompleted += new EventHandler(AuthComplete);
                OAuthWindow.Show();
            }
            else {
                _access_token = _oauthInfo["access_token"];
                if (_imageBuffer != null && _imageBuffer.Length > 0) {
                    this.Dispatcher.Invoke(new Action<InterfaceType>(Publish), InterfaceType.upload);
                }
                else {
                    this.Dispatcher.Invoke(new Action<InterfaceType>(Publish), InterfaceType.update);
                }
            }
        }

        private void AuthComplete(object sender, EventArgs e) {
            _oauthInfo = ((OAuthWindow)sender).OAuthInfo;
            this.Dispatcher.BeginInvoke(new Action<Dictionary<string, string>>(SaveSession), _oauthInfo);
            this.Dispatcher.BeginInvoke(new Action(LoadSession));
        }

        /// <summary>
        /// 
        /// </summary>
        private void Publish(InterfaceType type) {
            _timer.Start();
            wait_Image.Visibility = Visibility.Visible;

            _status = HttpUtility.UrlEncode(content.Text);
            StringBuilder sb = null;
            //ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CheckValidationResult);
            HttpWebRequest request = null;

            switch (type) {
                case InterfaceType.repost:
                    break;
                case InterfaceType.destroy:
                    break;
                case InterfaceType.update:
                    sb = new StringBuilder(_updateURL);
                    sb.AppendFormat("?access_token={0}&status={1}", _oauthInfo["access_token"], _status);
                    request = (HttpWebRequest)WebRequest.Create(sb.ToString());
                    request.Method = "POST";
                    request.ContentType = "application/x-www-form-urlencoded";
                    break;
                case InterfaceType.upload:

                    StringBuilder stringBuilder = new StringBuilder();
                    // 边界符
                    var boundary = "---------------" + DateTime.Now.Ticks.ToString("x");

                    request = (HttpWebRequest)WebRequest.Create(_uploadURL);
                    request.Headers["Authorization"] = string.Format("OAuth2 {0}", _access_token);

                    request.ContentType = "multipart/form-data; boundary=" + boundary;
                    request.Method = "POST";

                    stringBuilder.Append("\r\n--");
                    stringBuilder.Append(boundary);
                    stringBuilder.Append("\r\n");
                    stringBuilder.AppendFormat("Content-Disposition: form-data; name=\"{0}\"", "status");
                    stringBuilder.Append("\r\n\r\n");
                    stringBuilder.Append(_status);
                    stringBuilder.Append("\r\n\r\n");

                    stringBuilder.Append("--");
                    stringBuilder.Append(boundary);
                    stringBuilder.Append("\r\n");
                    stringBuilder.AppendFormat("Content-Disposition: form-data; name=\"{0}\";filename=\"{1}\"", "pic", Guid.NewGuid().ToString());
                    stringBuilder.Append("\r\n");
                    stringBuilder.Append("Content-Type: \"image/unknow\"");
                    stringBuilder.Append("\r\n");
                    stringBuilder.Append("Content-Transfer-Encoding: binary");
                    stringBuilder.Append("\r\n\r\n");

                    byte[] postHeaderBytes = Encoding.UTF8.GetBytes(stringBuilder.ToString());
                    byte[] postEndBytes = Encoding.UTF8.GetBytes("\r\n--" + boundary + "--" + "\r\n");

                    MemoryStream memoryStream = new MemoryStream();
                    memoryStream.Write(postHeaderBytes, 0, postHeaderBytes.Length);
                    memoryStream.Write(_imageBuffer, 0, _imageBuffer.Length);
                    memoryStream.Write(postEndBytes, 0, postEndBytes.Length);

                    var requestContent = memoryStream.ToArray();
                    request.ContentLength = requestContent.Length;

                    var requestStream = request.GetRequestStream();
                    requestStream.Write(requestContent, 0, requestContent.Length);

                    break;
                case InterfaceType.upload_url_text:
                    break;
                case InterfaceType.filter_create:
                    break;
                case InterfaceType.mentions_shield:
                    break;
                default:
                    break;
            }

            try {
                HttpWebResponse response = (HttpWebResponse)request.GetResponse();
                Stream stream = response.GetResponseStream();

                string result = string.Empty;

                using (StreamReader streamReader = new StreamReader(stream)) {
                    result = streamReader.ReadToEnd();
                }
            }
            catch (WebException webEx) {
                if (webEx.Response != null) {
                    using (StreamReader reader = new StreamReader(webEx.Response.GetResponseStream())) {
                        string errorInfo = reader.ReadToEnd();
                    }
                }

                throw;
            }


            content.Text = string.Empty;
            currentContent = string.Empty;
            _imageBuffer = null;
            insert_Image.Source = new BitmapImage(new Uri("/NO.I;component/Resources/btn_insert_pics_nor.png", UriKind.Relative));

            _timer.Stop();
            wait_Image.Visibility = Visibility.Hidden;
        }

        public static bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors) { // Always accept
            return true; //总是接受
        }

        private void Content_TextChanged(object sender, TextChangedEventArgs e) {
            byte[] contents = System.Text.Encoding.Default.GetBytes(content.Text);
            if (counter != null && display != null) {
                currentLength = contents.Length / 2;
                if (contents.Length > 280) {
                    TextChange[] change = new TextChange[e.Changes.Count];
                    e.Changes.CopyTo(change, 0);
                    int offset = change[0].Offset;
                    if (change[0].AddedLength > 0) {
                        content.Text = content.Text.Remove(offset, change[0].AddedLength);
                        content.Select(offset, 0);
                    }
                }
                counter.Text = currentLength + "/140";
                display.Text = (ContentMaxLength - currentLength).ToString();
            }
        }

        private void Content_GotFocus(object sender, RoutedEventArgs e) {
            content.Text = currentContent;
        }

        private void Content_LostFocus(object sender, RoutedEventArgs e) {
            if (string.IsNullOrEmpty(content.Text)) {
                content.Text = emptyContent;
                currentLength = 0;
                currentContent = string.Empty;
            }
            else {
                currentContent = content.Text;
            }
        }

        private void Window_Closed(object sender, EventArgs e) {

        }

        private void SaveSession(Dictionary<string, string> oauthInfo) {
            TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
            XmlDocument document = new XmlDocument();
            XmlDeclaration declaration = document.CreateXmlDeclaration("1.0", "utf-8", null);
            document.AppendChild(declaration);
            XmlElement rootElement = document.CreateElement("oauth");
            rootElement.SetAttribute("time", Convert.ToInt64(ts.TotalSeconds).ToString());
            document.AppendChild(rootElement);

            XmlElement subElement;
            foreach (var item in oauthInfo) {
                subElement = document.CreateElement(item.Key);
                subElement.InnerText = item.Value;
                rootElement.AppendChild(subElement);
            }
            using (StringWriter sw = new StringWriter()) {
                ResourceWriter rw = new ResourceWriter("NO.I.dat");
                XmlTextWriter tx = new XmlTextWriter(sw);
                document.WriteContentTo(tx);
                rw.AddResource("OAuthInfo", sw.ToString());
                rw.Close();
            }
        }

        private void LoadSession() {
            try {
                if (File.Exists("NO.I.dat")) {
                    _oauthInfo = new Dictionary<string, string>();
                    XmlDocument document = new XmlDocument();
                    using (ResourceSet rs = new ResourceSet("NO.I.dat")) {
                        document.LoadXml(rs.GetString("OAuthInfo"));
                    }
                    XmlNode rootNode = document.SelectSingleNode("oauth");
                    _startTime = Int64.Parse(rootNode.Attributes["time"].Value);
                    foreach (XmlElement item in rootNode.ChildNodes) {
                        _oauthInfo.Add(item.Name, item.InnerText);
                    }
                }
            }
            catch (Exception) {
                File.Delete("NO.I.dat");
            }
        }

        private bool CheckIsExprie() {
            bool isExpire = true;
            TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);

            if (_startTime > 0 && Convert.ToInt64(ts.TotalSeconds) - _startTime < Int64.Parse(_oauthInfo["expires_in"])) {
                isExpire = false;
            }

            return isExpire;
        }

        private void Wait(object sender, EventArgs e) {
            if (_currentFrame < _decoder.Frames.Count) {
                wait_Image.Source = _decoder.Frames[_currentFrame++];
            }
            else {
                _currentFrame = 0;
            }

        }

        private void Insert_Image_MouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e) {
            OpenFileDialog dialog = new OpenFileDialog();
            dialog.Title = "选择图片";
            dialog.Filter = "图像文件(JPEG、GIF、PNG)|*.gif;*.jpg;*.png";
            if ((bool)dialog.ShowDialog()) {
                _imageBuffer = File.ReadAllBytes(dialog.FileName);
                insert_Image.Source = new BitmapImage(new Uri("/NO.I;component/Resources/btn_insert_pics_res.png", UriKind.Relative));
            }
        }
    }
}
